﻿#region Copyright information
// 
// Copyright © 2005-2013 Yongkee Cho. All rights reserved.
// 
// This code is a part of the Biological Object Library and governed under the terms of the
// GNU Lesser General  Public License (LGPL) version 2.1 which accompanies this distribution.
// For more information on the LGPL, please visit http://bol.codeplex.com/license.
// 
// - Filename: Ridder.cs
// - Author: Yongkee Cho
// - Email: yongkeecho@gmail.com
// - Date Created: 2013-01-24 4:34 PM
// - Last Modified: 2013-01-25 3:59 PM
// 
#endregion
using System;

namespace BOL.Algorithms.Optimization
{
    /// <summary>
    /// Ridder's method
    /// </summary>
    public sealed class Ridder : RootFinderByValueBase
    {
        #region Private variables

        private double _fMin;
        private double _fMax;
        private double _mid;
        private double _fMid;

        #endregion

        #region Constructor

        public Ridder(Func<double, double> function, int numberOfIterations = 100, double tolerance = 1e-10, bool isVerbose = true)
            : base(function, numberOfIterations, tolerance, isVerbose) { }

        #endregion

        #region RootFinderByValueBase overriden

        protected override void Expect(double min, double max)
        {
            _fMin = Function(min);
            _fMax = Function(max);

            _mid = (min + max) * 0.5;
            _fMid = Function(_mid);

            Current = _mid + (_mid - min) * ((_fMin >= _fMax ? 1.0 : -1.0) * _fMid / Math.Sqrt(_fMid * _fMid - _fMin * _fMax));
            Value = Function(Current.Value);
        }

        protected override void Maximize(ref double min, ref double max)
        {
            if (Math.Sign(_fMid) == Math.Sign(Value))
            {
                min = _mid;
                if (Current.HasValue)
                    max = Current.Value;
            }
            else if (Math.Sign(_fMin) == Math.Sign(Value))
            {
                if (Current.HasValue)
                    max = Current.Value;
            }
            else
            {
                if (Current.HasValue)
                    max = Current.Value;
            }
        }

        #endregion
    }
}
